home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 15 / Amiga Plus Leser CD 15.iso / Tools / Development / MosaicSRC / libwww2 / HTAABrow.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-03-13  |  39.9 KB  |  1,467 lines

  1.  
  2. /* MODULE                            HTAABrow.c
  3. **        BROWSER SIDE ACCESS AUTHORIZATION MODULE
  4. **
  5. **    Containts the code for keeping track on server hostnames,
  6. **    port numbers, scheme names, usernames, passwords
  7. **    (and servers' public keys).
  8. **
  9. ** IMPORTANT:
  10. **    Routines in this module use dynamic allocation, but free
  11. **    automatically all the memory reserved by them.
  12. **
  13. **    Therefore the caller never has to (and never should)
  14. **    free() any object returned by these functions.
  15. **
  16. **    Therefore also all the strings returned by this package
  17. **    are only valid until the next call to the same function
  18. **    is made. This approach is selected, because of the nature
  19. **    of access authorization: no string returned by the package
  20. **    needs to be valid longer than until the next call.
  21. **
  22. **    This also makes it easy to plug the AA package in:
  23. **    you don't have to ponder whether to free() something
  24. **    here or is it done somewhere else (because it is always
  25. **    done somewhere else).
  26. **
  27. **    The strings that the package needs to store are copied
  28. **    so the original strings given as parameters to AA
  29. **    functions may be freed or modified with no side effects.
  30. **
  31. **    The AA package does not free() anything else than what
  32. **    it has itself allocated.
  33. **
  34. ** AUTHORS:
  35. **    AL    Ari Luotonen    luotonen@dxcern.cern.ch
  36. **
  37. ** HISTORY:
  38. **
  39. **
  40. ** BUGS:
  41. **
  42. **
  43. */
  44.  
  45. #include <string.h>        /* strchr() */
  46.  
  47. #include "HTUtils.h"
  48. #include "HTString.h"
  49. #include "HTParse.h"        /* URL parsing function        */
  50. #include "HTList.h"        /* HTList object        */
  51. #include "HTAlert.h"        /* HTConfirm(), HTPrompt()    */
  52. #include "HTAAUtil.h"        /* AA common to both sides    */
  53. #include "HTAssoc.h"        /* Assoc list            */
  54. #include "HTAABrow.h"        /* Implemented here        */
  55. #include "HTUU.h"        /* Uuencoding and uudecoding    */
  56.  
  57.  
  58.  
  59. /*
  60. ** Local datatype definitions
  61. **
  62. ** HTAAServer contains all the information about one server.
  63. */
  64. typedef struct {
  65.  
  66.     char *    hostname;    /* Host's name            */
  67.     int        portnumber;    /* Port number            */
  68.     HTList *    setups;        /* List of protection setups    */
  69.                                 /* on this server; i.e. valid    */
  70.                                 /* authentication schemes and    */
  71.                                 /* templates when to use them.    */
  72.                                 /* This is actually a list of    */
  73.                                 /* HTAASetup objects.        */
  74.     HTList *    realms;        /* Information about passwords    */
  75. } HTAAServer;
  76.  
  77.  
  78. /*
  79. ** HTAASetup contains information about one server's one
  80. ** protected tree of documents.
  81. */
  82. typedef struct {
  83.     HTAAServer *server;        /* Which server serves this tree         */
  84.     char *    template;    /* Template for this tree             */
  85.     HTList *    valid_schemes;    /* Valid authentic.schemes                */
  86.     HTAssocList**scheme_specifics;/* Scheme specific params             */
  87.     BOOL    retry;        /* Failed last time -- reprompt (or whatever)*/
  88. } HTAASetup;
  89.  
  90.  
  91. /*
  92. ** Information about usernames and passwords in
  93. ** Basic and Pubkey authentication schemes;
  94. */
  95. typedef struct {
  96.     char *    realmname;    /* Password domain name        */
  97.     char *    username;    /* Username in that domain    */
  98.     char *    password;    /* Corresponding password    */
  99. } HTAARealm;
  100.  
  101.  
  102.  
  103. /*
  104. ** Module-wide global variables
  105. */
  106.  
  107. PRIVATE HTList *server_table    = NULL;    /* Browser's info about servers         */
  108. PRIVATE char *secret_key    = NULL;    /* Browser's latest secret key       */
  109. PRIVATE HTAASetup *current_setup= NULL;    /* The server setup we are currently */
  110.                                         /* talking to                 */
  111. PRIVATE char *current_hostname    = NULL;    /* The server's name and portnumber  */
  112. PRIVATE int current_portnumber    = 80;    /* where we are currently trying to  */
  113.                                         /* connect.                 */
  114. PRIVATE char *current_docname    = NULL;    /* The document's name we are        */
  115.                                         /* trying to access.             */
  116.  
  117. #ifdef PEM_AUTH
  118. PUBLIC char *HTAA_PEMencrypt = NULL;    /* The command used to encrypt a PEM message */
  119. PUBLIC char *HTAA_PEMdecrypt = NULL;    /* The command used to decrypt a PEM message */
  120. PUBLIC char *HTAA_PEMentity = NULL;     /* the client's entity name */
  121. PUBLIC char *HTAA_PGPencrypt = NULL;    /* The command used to encrypt a PGP message */
  122. PUBLIC char *HTAA_PGPdecrypt = NULL;    /* The command used to decrypt a PGP message */
  123. PUBLIC char *HTAA_PGPentity = NULL;    /* the client's entity name */
  124. /* #define TRACE 1  !!! */
  125. #endif /* PEM_AUTH */
  126.  
  127.  
  128.  
  129.  
  130. /**************************** HTAAServer ***********************************/
  131.  
  132.  
  133. /* PRIVATE                        HTAAServer_new()
  134. **        ALLOCATE A NEW NODE TO HOLD SERVER INFO
  135. **        AND ADD IT TO THE LIST OF SERVERS
  136. ** ON ENTRY:
  137. **    hostname    is the name of the host that the server
  138. **            is running in.
  139. **    portnumber    is the portnumber which the server listens.
  140. **
  141. ** ON EXIT:
  142. **    returns        the newly-allocated node with all the strings
  143. **            duplicated.
  144. **            Strings will be automatically freed by
  145. **            the function HTAAServer_delete(), which also
  146. **            frees the node itself.
  147. */
  148. PRIVATE HTAAServer *HTAAServer_new ARGS2(CONST char*,    hostname,
  149.                      int,        portnumber)
  150. {
  151.     HTAAServer *server;
  152.  
  153.     if (!(server = (HTAAServer *)malloc(sizeof(HTAAServer))))
  154.     outofmem(__FILE__, "HTAAServer_new");
  155.  
  156.     server->hostname    = NULL;
  157.     server->portnumber    = (portnumber > 0 ? portnumber : 80);
  158.     server->setups    = HTList_new();
  159.     server->realms    = HTList_new();
  160.  
  161.     if (hostname) StrAllocCopy(server->hostname, hostname);
  162.  
  163.     if (!server_table) server_table = HTList_new();
  164.     
  165.     HTList_addObject(server_table, (void*)server);
  166.  
  167.     return server;
  168. }
  169.  
  170.  
  171. /* PRIVATE                        HTAAServer_delete()
  172. **
  173. **    DELETE THE ENTRY FOR THE SERVER FROM THE HOST TABLE,
  174. **    AND FREE THE MEMORY USED BY IT.
  175. **
  176. ** ON ENTRY:
  177. **    killme        points to the HTAAServer to be freed.
  178. **
  179. ** ON EXIT:
  180. **    returns        nothing.
  181. */
  182. #ifdef PEM_AUTH
  183. PRIVATE void HTAASetup_delete();    /* Forward */
  184. PRIVATE void HTAAServer_delete();    /* Forward */
  185.  
  186. PRIVATE void HTAAServerTable_delete ARGS1(HTList *, table)
  187. {
  188.     if (table) {
  189.     HTAAServer *server;
  190.  
  191.     while (NULL != (server = (HTAAServer*)HTList_nextObject(table)))
  192.         HTAAServer_delete(server);
  193.  
  194.     HTList_delete(table);
  195.  
  196.     server_table = NULL;
  197.     }
  198. }
  199.  
  200. PRIVATE void HTAAServer_delete ARGS1(HTAAServer *, killme)
  201. {
  202.     if (killme) {
  203.     HTList *cur1 = killme->setups;
  204.     HTList *cur2 = killme->realms;
  205.     HTAASetup *setup;
  206.     HTAARealm *realm;
  207.  
  208.     while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur1)))
  209.         HTAASetup_delete(setup);
  210.     HTList_delete(killme->setups);
  211.  
  212.     while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur2)))
  213.         ;    /* This sould free() the realm */
  214.     HTList_delete(killme->realms);
  215.  
  216.     FREE(killme->hostname);
  217.  
  218.     HTList_removeObject(server_table, (void*)killme);
  219.  
  220.     free(killme);
  221.     }
  222. }
  223. #endif /* PEM_AUTH */
  224.  
  225.  
  226. /* PRIVATE                        HTAAServer_lookup()
  227. **        LOOK UP SERVER BY HOSTNAME AND PORTNUMBER
  228. ** ON ENTRY:
  229. **    hostname    obvious.
  230. **    portnumber    if non-positive defaults to 80.
  231. **
  232. **    Looks up the server in the module-global server_table.
  233. **
  234. ** ON EXIT:
  235. **    returns        pointer to a HTAAServer structure
  236. **            representing the looked-up server.
  237. **            NULL, if not found.
  238. */
  239. PRIVATE HTAAServer *HTAAServer_lookup ARGS2(CONST char *, hostname,
  240.                         int,      portnumber)
  241. {
  242.     if (hostname) {
  243.     HTList *cur = server_table;
  244.     HTAAServer *server;
  245.  
  246.     if (portnumber <= 0) portnumber = 80;
  247.  
  248.     while (NULL != (server = (HTAAServer*)HTList_nextObject(cur))) {
  249.         if (server->portnumber == portnumber  &&
  250.         0==strcmp(server->hostname, hostname))
  251.         return server;
  252.     }
  253.     }
  254.     return NULL;    /* NULL parameter, or not found */
  255. }
  256.  
  257.  
  258.  
  259.  
  260. /*************************** HTAASetup *******************************/    
  261.  
  262.  
  263. /* PRIVATE                        HTAASetup_lookup()
  264. **    FIGURE OUT WHICH AUTHENTICATION SETUP THE SERVER
  265. **    IS USING FOR A GIVEN FILE ON A GIVEN HOST AND PORT
  266. **
  267. ** ON ENTRY:
  268. **    hostname    is the name of the server host machine.
  269. **    portnumber    is the port that the server is running in.
  270. **    docname        is the (URL-)pathname of the document we
  271. **            are trying to access.
  272. **
  273. **     This function goes through the information known about
  274. **    all the setups of the server, and finds out if the given
  275. **    filename resides in one of the protected directories.
  276. **
  277. ** ON EXIT:
  278. **    returns        NULL if no match.
  279. **            Otherwise, a HTAASetup structure representing
  280. **            the protected server setup on the corresponding
  281. **            document tree.
  282. **            
  283. */
  284. PRIVATE HTAASetup *HTAASetup_lookup ARGS3(CONST char *, hostname,
  285.                       int,        portnumber,
  286.                       CONST char *, docname)
  287. {
  288.     HTAAServer *server;
  289.     HTAASetup *setup;
  290.  
  291.     if (portnumber <= 0) portnumber = 80;
  292.  
  293.     if (hostname && docname && *hostname && *docname &&
  294.     NULL != (server = HTAAServer_lookup(hostname, portnumber))) {
  295.  
  296.     HTList *cur = server->setups;
  297.  
  298.     if (TRACE) fprintf(stderr, "%s (%s:%d:%s)\n",
  299.                "HTAASetup_lookup: resolving setup for",
  300.                hostname, portnumber, docname);
  301.  
  302.     while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur))) {
  303.         if (HTAA_templateMatch(setup->template, docname)) {
  304.         if (TRACE) fprintf(stderr, "%s `%s' %s `%s'\n",
  305.                    "HTAASetup_lookup:", docname,
  306.                    "matched template", setup->template);
  307.         return setup;
  308.         }
  309.         else if (TRACE) fprintf(stderr, "%s `%s' %s `%s'\n",
  310.                     "HTAASetup_lookup:", docname,
  311.                     "did NOT match template", setup->template);
  312.     } /* while setups remain */
  313.     } /* if valid parameters and server found */
  314.  
  315.     if (TRACE) fprintf(stderr, "%s `%s' %s\n",
  316.                "HTAASetup_lookup: No template matched",
  317.                (docname ? docname : "(null)"),
  318.                "(so probably not protected)");
  319.  
  320.     return NULL;    /* NULL in parameters, or not found */
  321. }
  322.  
  323.  
  324.  
  325.  
  326. /* PRIVATE                        HTAASetup_new()
  327. **            CREATE A NEW SETUP NODE
  328. ** ON ENTRY:
  329. **    server        is a pointer to a HTAAServer structure
  330. **            to which this setup belongs.
  331. **    template    documents matching this template
  332. **            are protected according to this setup.
  333. **    valid_schemes    a list containing all valid authentication
  334. **            schemes for this setup.
  335. **            If NULL, all schemes are disallowed.
  336. **    scheme_specifics is an array of assoc lists, which
  337. **            contain scheme specific parameters given
  338. **            by server in Authenticate: fields.
  339. **            If NULL, all scheme specifics are
  340. **            set to NULL.
  341. ** ON EXIT:
  342. **    returns        a new HTAASetup node, and also adds it as
  343. **            part of the HTAAServer given as parameter.
  344. */
  345. PRIVATE HTAASetup *HTAASetup_new ARGS4(HTAAServer *,    server,
  346.                        char *,        template,
  347.                        HTList *,    valid_schemes,
  348.                        HTAssocList **,    scheme_specifics)
  349. {
  350.     HTAASetup *setup;
  351.  
  352.     if (!server || !template || !*template) return NULL;
  353.  
  354.     if (!(setup = (HTAASetup*)malloc(sizeof(HTAASetup))))
  355.     outofmem(__FILE__, "HTAASetup_new");
  356.  
  357.     setup->retry = NO;
  358.     setup->server = server;
  359.     setup->template = NULL;
  360.     if (template) StrAllocCopy(setup->template, template);
  361.     setup->valid_schemes = valid_schemes;
  362.     setup->scheme_specifics = scheme_specifics;
  363.  
  364.     HTList_addObject(server->setups, (void*)setup);
  365.  
  366.     return setup;
  367. }
  368.  
  369.  
  370.  
  371. /* PRIVATE                        HTAASetup_delete()
  372. **            FREE A HTAASetup STRUCTURE
  373. ** ON ENTRY:
  374. **    killme        is a pointer to the structure to free().
  375. **
  376. ** ON EXIT:
  377. **    returns        nothing.
  378. */
  379. #ifdef PEM_AUTH
  380. PRIVATE void HTAASetup_delete ARGS1(HTAASetup *, killme)
  381. {
  382.     int scheme;
  383.  
  384.     if (killme) {
  385.     if (killme->template) free(killme->template);
  386.     if (killme->valid_schemes)
  387.         HTList_delete(killme->valid_schemes);
  388.     for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++)
  389.         if (killme->scheme_specifics[scheme])
  390.         HTAssocList_delete(killme->scheme_specifics[scheme]);
  391.     free(killme);
  392.     }
  393. }
  394. #endif /* PEM_AUTH */
  395.  
  396.  
  397.  
  398. /* PRIVATE                    HTAASetup_updateSpecifics()
  399. *        COPY SCHEME SPECIFIC PARAMETERS
  400. **        TO HTAASetup STRUCTURE
  401. ** ON ENTRY:
  402. **    setup        destination setup structure.
  403. **    specifics    string array containing scheme
  404. **            specific parameters for each scheme.
  405. **            If NULL, all the scheme specific
  406. **            parameters are set to NULL.
  407. **
  408. ** ON EXIT:
  409. **    returns        nothing.
  410. */
  411. PRIVATE void HTAASetup_updateSpecifics ARGS2(HTAASetup *,    setup,
  412.                          HTAssocList **,    specifics)
  413. {
  414.     int scheme;
  415.  
  416.     if (setup) {
  417.     if (setup->scheme_specifics) {
  418.         for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++) {
  419.         if (setup->scheme_specifics[scheme])
  420.             HTAssocList_delete(setup->scheme_specifics[scheme]);
  421.         }
  422.         free(setup->scheme_specifics);
  423.     }
  424.     setup->scheme_specifics = specifics;
  425.     }
  426. }
  427.  
  428.  
  429.  
  430.  
  431. /*************************** HTAARealm **********************************/
  432.  
  433. /* PRIVATE                         HTAARealm_lookup()
  434. **        LOOKUP HTAARealm STRUCTURE BY REALM NAME
  435. ** ON ENTRY:
  436. **    realm_table    a list of realm objects.
  437. **    realmname    is the name of realm to look for.
  438. **
  439. ** ON EXIT:
  440. **    returns        the realm.  NULL, if not found.
  441. */
  442. PRIVATE HTAARealm *HTAARealm_lookup ARGS2(HTList *,    realm_table,
  443.                       CONST char *, realmname)
  444. {
  445.     if (realm_table && realmname) {
  446.     HTList *cur = realm_table;
  447.     HTAARealm *realm;
  448.     
  449.     while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur))) {
  450.         if (0==strcmp(realm->realmname, realmname))
  451.         return realm;
  452.     }
  453.     }
  454.     return NULL;    /* No table, NULL param, or not found */
  455. }
  456.  
  457.  
  458.  
  459. /* PRIVATE                        HTAARealm_new()
  460. **        CREATE A NODE CONTAINING USERNAME AND
  461. **        PASSWORD USED FOR THE GIVEN REALM.
  462. **        IF REALM ALREADY EXISTS, CHANGE
  463. **        USERNAME/PASSWORD.
  464. ** ON ENTRY:
  465. **    realm_table    a list of realms to where to add
  466. **            the new one, too.
  467. **    realmname    is the name of the password domain.
  468. **    username    and
  469. **    password    are what you can expect them to be.
  470. **
  471. ** ON EXIT:
  472. **    returns        the created realm.
  473. */
  474. PRIVATE HTAARealm *HTAARealm_new ARGS4(HTList *,    realm_table,
  475.                        CONST char *,    realmname,
  476.                        CONST char *,    username,
  477.                        CONST char *,    password)
  478. {
  479.     HTAARealm *realm;
  480.  
  481.     realm = HTAARealm_lookup(realm_table, realmname);
  482.  
  483.     if (!realm) {
  484.     if (!(realm = (HTAARealm*)malloc(sizeof(HTAARealm))))
  485.         outofmem(__FILE__, "HTAARealm_new");
  486.     realm->realmname = NULL;
  487.     realm->username = NULL;
  488.     realm->password = NULL;
  489.     StrAllocCopy(realm->realmname, realmname);
  490.     if (realm_table) HTList_addObject(realm_table, (void*)realm);
  491.     }
  492.     if (username) StrAllocCopy(realm->username, username);
  493.     if (password) StrAllocCopy(realm->password, password);
  494.  
  495.     return realm;
  496. }
  497.  
  498.  
  499. /* BROWSER PRIVATE                    HTAA_selectScheme()
  500. **        SELECT THE AUTHENTICATION SCHEME TO USE
  501. ** ON ENTRY:
  502. **    setup    is the server setup structure which can
  503. **        be used to make the decision about the
  504. **        used scheme.
  505. **
  506. **    When new authentication methods are added to library
  507. **    this function makes the decision about which one to
  508. **    use at a given time.  This can be done by inspecting
  509. **    environment variables etc.
  510. **
  511. **    Currently only searches for the first valid scheme,
  512. **    and if nothing found suggests Basic scheme;
  513. **
  514. ** ON EXIT:
  515. **    returns    the authentication scheme to use.
  516. */
  517. PRIVATE HTAAScheme HTAA_selectScheme ARGS1(HTAASetup *, setup)
  518. {
  519.     HTAAScheme scheme;
  520.  
  521.     if (setup && setup->valid_schemes) {
  522.     for (scheme=HTAA_BASIC; scheme < HTAA_MAX_SCHEMES; scheme++)
  523.         if (-1 < HTList_indexOf(setup->valid_schemes, (void*)scheme))
  524.         return scheme;
  525.     }
  526.     return HTAA_BASIC;
  527. }
  528.  
  529.  
  530. #ifdef PEM_AUTH
  531. /*
  532.  * PRIVATE                                              compose_auth_pem()
  533.  *              COMPOSE AUTHORIZATION STRING FOR PEM SCHEME
  534.  * 
  535.  * ON ENTRY:
  536.  *      setup           is a pointer to an HTAASetup structure
  537.  * ON EXIT:
  538.  *      returns         an authorization line for an HTTP header,
  539.  *                      or NULL
  540.  * 
  541.  * The string returned by this routine should not be freed, it will be done 
  542.  * like the others.
  543.  *
  544.  */
  545.  
  546. PRIVATE char *compose_auth_pem ARGS1(HTAASetup *,setup) 
  547. {
  548.     static char *result = NULL;
  549.     int type;
  550.     char *entity,*type_name;
  551.  
  552.     FREE(result);
  553.  
  554.     type = HTAA_selectScheme(current_setup);
  555.     if(type == HTAA_PEM) {
  556.         entity = HTAA_PEMentity;
  557.         type_name = "PEM";
  558.     } else {
  559.         entity = HTAA_PGPentity;
  560.         type_name = "PGP";
  561.     }
  562.  
  563.     /* 28 = strlen(Authorization: XXX entity="") */
  564.     /* 3 = CRLF\0 */
  565.     result = (char *)malloc(33+strlen(entity));
  566.     if(!result)
  567.         outofmem(__FILE__,"compose_auth_pem");
  568.     sprintf(result,"Authorization: %s entity=\"%s\"%c%c",
  569.             type_name,entity,CR,LF);
  570.     return result;
  571. }
  572.  
  573. /*
  574.  * PUBLIC                                               HTAA_makecommand()
  575.  * 
  576.  *              ENCRYPT AN HTTP REQUEST, AND ENCAPSULATE IT IN
  577.  *              A NEW HTTP PEM AUTHORIZED REQUEST
  578.  * 
  579.  * ON ENTRY:
  580.  *      command         the HTTP request
  581.  *      body            ptr to a char ptr for body of text
  582.  *      bl              pointer to int of length of this body
  583.  * 
  584.  * ON EXIT:
  585.  *      returns         the new HTTP request with PEM
  586.  * 
  587.  * Unlike the rest of the AA stuff, you must free this string. 
  588.  *
  589.  * This function *requires* that the HTAA_composeAuth function has been 
  590.  * called prior to it.
  591.  * 
  592.  */
  593.  
  594. #ifndef STDIN_FILENO
  595. #define STDIN_FILENO 0
  596. #endif
  597.  
  598. #ifndef STDOUT_FILENO
  599. #define STDOUT_FILENO 1
  600. #endif
  601.  
  602. #define HTTP_PEM_HEADER "GET / HTTP/1.0\r\nContent-type: application/x-www-pem-request\r\n"
  603. #define HTTP_PGP_HEADER "GET / HTTP/1.0\r\nContent-type: application/x-www-pgp-request\r\n"
  604.  
  605. PUBLIC char *HTAA_makecommand ARGS3(char *,command,char **,body,int *,bl)
  606. {
  607.     static char *result = NULL;
  608.     int p[2];                         /* pipe from libw3 to pem prog */
  609.     int tfd;                          /* a temp file for output of pem prog */
  610.     char tn[L_tmpnam];                /* temp file name */
  611.     struct stat finfo;                /* stat buffer for tmp file */
  612.     int pid;                          /* pid for fork */
  613.     char *t;                          /* general purpose temp string */
  614.     char *remote_entity;              /* the entity name the server gave us */
  615.     int nr,l;                         /* counters */
  616.     int type;                         /* type of encryption */
  617.     char *encrypt,*head;              /* set from gbls according to type */
  618.  
  619.     /* HTAA_composeAuth will set current_setup to NULL if no auth needed */
  620.     if(!current_setup)
  621.         return command;
  622.     type = HTAA_selectScheme(current_setup);
  623.     if((type != HTAA_PEM) && (type != HTAA_PGP))
  624.         return command;
  625.  
  626.     encrypt = (type == HTAA_PEM ? HTAA_PEMencrypt : HTAA_PGPencrypt);
  627.     if(TRACE) 
  628.         fprintf(stderr,"Encrypt command is %s\n",encrypt);
  629.  
  630.     remote_entity = 
  631.         HTAssocList_lookup(current_setup->scheme_specifics[type],"entity");
  632.     if((!remote_entity) || (!encrypt))
  633.         return command;
  634.  
  635.     tmpnam(tn);
  636.  
  637.     if(TRACE) {
  638.         fprintf(stderr,"HTAA_makecommand: tn is %s\n",tn);
  639.         fprintf(stderr,"HTAA_makecommand: remote_entity is %s\n",
  640.                 remote_entity);
  641.         fprintf(stderr,"HTAA_makecommand: tn is %s\n",tn);
  642.     }
  643.  
  644.     if(pipe(p) < 0) {
  645.         fprintf(stderr,"%s(HTAA_makecommand): pipe failed\n",__FILE__);
  646.         perror("pipe");
  647.         exit(1);
  648.     }
  649.     if((pid = fork()) < 0) {
  650.         fprintf(stderr,"%s(HTAA_makecommand): fork failed\n",__FILE__);
  651.         perror("fork");
  652.         exit(1);
  653.     }
  654.     if(!pid) {
  655.         char *argv0;
  656.         close(p[1]);
  657.         if(p[0] != STDIN_FILENO) {
  658.             dup2(p[0],STDIN_FILENO);
  659.             close(p[0]);
  660.         }
  661.         if((tfd = open(tn,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR)) == -1) {
  662.             fprintf(stderr,"%s(HTAA_makecommand): open failed\n",__FILE__);
  663.             perror("open");
  664.             exit(1);
  665.         }
  666.         if(tfd != STDOUT_FILENO) {
  667.             dup2(tfd,STDOUT_FILENO);
  668.             close(tfd);
  669.         }
  670.         if(!(argv0 = strrchr(encrypt,'/')))
  671.             argv0 = encrypt;
  672.         else
  673.             ++argv0;
  674.         if(execlp(encrypt,argv0,remote_entity,(char *)0) == -1) {
  675.             fprintf(stderr,"%s(HTAA_makecommand): exec of %s failed\n",
  676.                     __FILE__,encrypt);
  677.             perror("execlp");
  678.             exit(1);
  679.         }
  680.     }
  681.     else {
  682.         close(p[0]);
  683.         write(p[1],command,strlen(command));
  684.         close(p[1]);
  685.         wait(NULL);
  686.     }
  687.     head = (type == HTAA_PEM ? HTTP_PEM_HEADER : HTTP_PGP_HEADER);
  688.     result = (char *)malloc(strlen(head) + 1);
  689.     if(!result)
  690.         outofmem(__FILE__,"HTAA_makecommand");
  691.     strcpy(result,head);
  692.  
  693.     StrAllocCat(result,compose_auth_pem(current_setup));
  694.  
  695.     if(stat(tn,&finfo) == -1) {
  696.         fprintf(stderr,"%s(HTAA_makecommand): could not stat %s\n",
  697.                 __FILE__,tn);
  698.         perror("stat");
  699.         exit(1);
  700.     }
  701.     /* 16 = strlen(content-length: ) */
  702.     /* 20 = max. length of file size */
  703.     t = (char *)malloc(16+10+5);
  704.     if(!t)
  705.         outofmem(__FILE__,"HTAA_makecommand");
  706.     sprintf(t,"Content-length: %d%c%c%c%c",finfo.st_size,CR,LF,CR,LF);
  707.     StrAllocCat(result,t);
  708.     free(t);
  709.     *bl = finfo.st_size;
  710.     *body = (char *)malloc(finfo.st_size);
  711.     if(!(*body))
  712.         outofmem(__FILE__,"HTAA_makecommand");
  713.  
  714.     if((tfd = open(tn,O_RDONLY)) == -1) {
  715.         fprintf(stderr,"%s(HTAA_makecommand): could not open temp file %s\n",
  716.                 __FILE__,tn);
  717.         perror("open");
  718.         exit(1);
  719.     }
  720.     nr = read(tfd,*body,finfo.st_size);
  721.     if(nr != finfo.st_size) {
  722.         fprintf(stderr,"%s(HTAA_makecommand): read of %s got %d, should get %d.\n",
  723.                 __FILE__,tn,nr,finfo.st_size);
  724.         perror("read");
  725.         exit(1);
  726.     }
  727.     close(tfd);
  728.     if(unlink(tn) == -1)
  729.         fprintf(stderr,"HTAA_makecommand: unlink of %s failed, errno is %d\n",
  730.                 tn,errno);
  731.     FREE(command);
  732.     if(TRACE)
  733.         fprintf(stderr,"Sending the following:\n\n%s",result);
  734.     return result;
  735. }
  736.  
  737. /*
  738.  * PUBLIC                                        HTAA_switchPEMresponse()
  739.  * 
  740.  *           IF DOING PEM AUTHENTICATION, TAKES A SOCKET WHICH 
  741.  *           IS A REPONSE FROM AN HTTP SERVER, PULLS OFF THE PHONY
  742.  *           HEADER, DECRYPTS, AND RETURNS A FILE DESCRIPTOR TO A 
  743.  *           TEMP FILE WITH THE REAL RESPONSE.
  744.  * 
  745.  * ON ENTRY:
  746.  *      sfd             pointer to the socket descriptor to the server
  747.  * 
  748.  * ON EXIT:
  749.  *      returns         the socket (if no PEM encrypt.), or a file desc.
  750.  *                      to the real request. -1 on error.
  751.  * 
  752.  */
  753.  
  754. static char *decrypt_tmpfile;
  755. #include "HTFWriter.h"
  756.  
  757.  
  758. PUBLIC int HTAA_switchPEMresponse ARGS3(char *, start_of_data,
  759.                     int,    length,
  760.                     int *,  sfd)
  761. {
  762.     int tfd,rfd;
  763.     FILE *t_fp;
  764.     char tn[L_tmpnam],*cmd;
  765.     HTStream *s;
  766.     int type;
  767.     char *decrypt;
  768.     char *remote_entity;
  769.  
  770.     if(!current_setup)
  771.         return -2;
  772.     type = HTAA_selectScheme(current_setup);
  773.     if((type != HTAA_PEM) && (type != HTAA_PGP))
  774.         return -2;
  775.     decrypt = (type == HTAA_PEM ? HTAA_PEMdecrypt : HTAA_PGPdecrypt);
  776.  
  777.     if (!decrypt)
  778.     return -2;
  779.  
  780.     remote_entity = 
  781.         HTAssocList_lookup(current_setup->scheme_specifics[type],"entity");
  782.  
  783.     tmpnam(tn);
  784.     if(TRACE)
  785.         fprintf(stderr,"tn is now %s\n",tn);
  786.     decrypt_tmpfile = (char *)malloc(strlen(tn) + 1);
  787.     strcpy(decrypt_tmpfile,tn);
  788.  
  789.     if(!(t_fp = fopen(tn,"w"))) {
  790.         fprintf(stderr,"%s(HTAA_switchPEMresponse): unable to write to %s",
  791.                 __FILE__,tn);
  792.         perror("fopen");
  793.         return -1;
  794.     }
  795.  
  796.     /* stuff in extra data */
  797.     if (length > 0) {
  798.     char con_type[500];
  799.     char *tptr;
  800.  
  801.     /* strip off fake header */
  802.     con_type[0] = '\0';
  803.     tptr = start_of_data;
  804.     if (*tptr != LF)
  805.     {
  806.         char field[500];
  807.  
  808.         sscanf(tptr, " %s", field);
  809.         if (strcasecomp(field, "Content-type:") == 0)
  810.         {
  811.             tptr = strchr(tptr, ':');
  812.             if (tptr != NULL)
  813.             {
  814.                 tptr++;
  815.                 sscanf(tptr, " %s", con_type);
  816.             }
  817.         }
  818.         if (tptr != NULL)
  819.         {
  820.             tptr = strchr(tptr, LF);
  821.         }
  822.     }
  823.     while (tptr != NULL)
  824.     {
  825.         char field[500];
  826.  
  827.         tptr++;
  828.         if (*tptr == LF)
  829.         {
  830.             tptr++;
  831.             length = length - (tptr - start_of_data);
  832.             start_of_data = tptr;
  833.             break;
  834.         }
  835.  
  836.         sscanf(tptr, " %s", field);
  837.         if ((con_type[0] == '\0')&&(strcasecomp(field, "Content-type:") == 0))
  838.         {
  839.             tptr = strchr(tptr, ':');
  840.             if (tptr != NULL)
  841.             {
  842.                 tptr++;
  843.                 sscanf(tptr, " %s", con_type);
  844.             }
  845.         }
  846.         if (tptr != NULL)
  847.         {
  848.             tptr = strchr(tptr, LF);
  849.         }
  850.     }
  851.     if (tptr != NULL)
  852.     {
  853.         fwrite(start_of_data, length, 1, t_fp);
  854.     }
  855.  
  856.     if (con_type[0] != '\0')
  857.     {
  858.         if ((type == HTAA_PEM)&&(strcmp(con_type,
  859.             "application/x-www-pem-reply") != 0))
  860.         {
  861.             return -3;
  862.         }
  863.         if ((type == HTAA_PGP)&&(strcmp(con_type,
  864.             "application/x-www-pgp-reply") != 0))
  865.         {
  866.             return -3;
  867.         }
  868.     }
  869.     }
  870.  
  871.     /* Oh, come on, TWO is an error code!? */
  872.     if(HTOutputBinary(sfd,t_fp) == 2) {
  873.         fprintf(stderr,"%s(HTAA_switchPEMresponse): error reading %s",
  874.                 __FILE__,tn);
  875.         return -1;
  876.     }
  877.     fflush(t_fp);
  878.     fclose(t_fp);
  879.     NETCLOSE(sfd);
  880.  
  881.     if(!(cmd = (char *)malloc(strlen(remote_entity)+strlen(decrypt)+
  882.                               (2*strlen(tn))+19)))
  883.         outofmem(__FILE__,"HTAA_switchPEMresponse");
  884.     
  885.     sprintf(cmd,"%s %s < %s > %s.1",decrypt,remote_entity,tn,tn);
  886.     system(cmd); /* aaack we really should do this work fork and pipes */
  887.     sprintf(cmd,"mv %s.1 %s",tn,tn);
  888.     system(cmd);
  889.     free(cmd);
  890.  
  891.     if((tfd = open(tn,O_RDONLY)) == -1) {
  892.         fprintf(stderr,
  893.                 "%s(HTAA_switchPEMresponse): could not open tmp file %s",
  894.                 __FILE__,tn);
  895.         perror("open");
  896.         return -1;
  897.     }
  898.     return tfd;
  899. }
  900.  
  901. /*
  902.  * PUBLIC                                        HTAA_PEMclose()
  903.  * 
  904.  * This takes a file descriptor returned by HTAA_switchPEMresponse
  905.  * and closes it if necessary, unlinking the temp file
  906.  * 
  907.  */
  908.  
  909. PUBLIC int HTAA_PEMclose ARGS1(int,fd) 
  910. {
  911.     int type;
  912.     if(!current_setup)
  913.         return 0;
  914.     type = HTAA_selectScheme(current_setup);
  915.     if((type != HTAA_PEM) && (type != HTAA_PGP))
  916.         return 0;
  917.  
  918.     close(fd);
  919.     if(TRACE)
  920.         fprintf(stderr,"unlinking %s\n",decrypt_tmpfile);
  921.     if(unlink(decrypt_tmpfile) == -1)
  922.         fprintf(stderr,"unlink failed for %s, errno is %d\n",decrypt_tmpfile,
  923.                 errno);
  924.     free(decrypt_tmpfile);
  925.     decrypt_tmpfile = NULL;
  926.     return 1;
  927. }
  928. #endif /* PEM_AUTH */
  929.  
  930. /***************** Basic and Pubkey Authentication ************************/
  931.  
  932. /* PRIVATE                        compose_auth_string()
  933. **
  934. **        COMPOSE Basic OR Pubkey AUTHENTICATION STRING;
  935. **        PROMPTS FOR USERNAME AND PASSWORD IF NEEDED
  936. **
  937. ** ON ENTRY:
  938. **    scheme        is either HTAA_BASIC or HTAA_PUBKEY.
  939. **    realmname    is the password domain name.
  940. **
  941. ** ON EXIT:
  942. **    returns        a newly composed authorization string,
  943. **            (with, of course, a newly generated secret
  944. **            key and fresh timestamp, if Pubkey-scheme
  945. **            is being used).
  946. ** NOTE:
  947. **    Like throughout the entire AA package, no string or structure
  948. **    returned by AA package needs to (or should) be freed.
  949. **
  950. */
  951. PRIVATE char *compose_auth_string ARGS2(HTAAScheme,    scheme,
  952.                     HTAASetup *,    setup)
  953. {
  954.     static char *result = NULL;    /* Uuencoded presentation, the result */
  955.     char *cleartext = NULL;    /* Cleartext presentation */
  956.     char *ciphertext = NULL;    /* Encrypted presentation */
  957.     int len;
  958.     char *username;
  959.     char *password;
  960.     char *realmname;
  961.     HTAARealm *realm;
  962.     char *inet_addr = "0.0.0.0";    /* Change... @@@@ */
  963.     char *timestamp = "42";        /* ... these @@@@ */
  964.     
  965.  
  966.     FREE(result);    /* From previous call */
  967.  
  968.     if ((scheme != HTAA_BASIC && scheme != HTAA_PUBKEY) || !setup ||
  969.     !setup->scheme_specifics || !setup->scheme_specifics[scheme] ||
  970.     !setup->server  ||  !setup->server->realms)
  971.     return "";
  972.  
  973.     realmname = HTAssocList_lookup(setup->scheme_specifics[scheme], "realm");
  974.     if (!realmname) return "";
  975.  
  976.     realm = HTAARealm_lookup(setup->server->realms, realmname);
  977.     if (!realm || setup->retry) {
  978.     char msg[2048];
  979.  
  980.     if (!realm) {
  981.         if (TRACE) fprintf(stderr, "%s `%s' %s\n",
  982.                    "compose_auth_string: realm:", realmname,
  983.                    "not found -- creating");
  984.         realm = HTAARealm_new(setup->server->realms, realmname, NULL,NULL);
  985.         sprintf(msg,
  986.             "Document is protected.\nEnter username for %s at %s: ",
  987.             realm->realmname,
  988.             setup->server->hostname ? setup->server->hostname : "??");
  989.         realm->username =
  990.         HTPrompt(msg, realm->username);
  991.             /* Added by marca. */
  992.             if (!realm->username)
  993.               return "";
  994.     }
  995.     else {
  996.         sprintf(msg,"Enter username for %s at %s: ", realm->realmname,
  997.             setup->server->hostname ? setup->server->hostname : "??");
  998.         username = HTPrompt(msg, realm->username);
  999.         FREE(realm->username);
  1000.         realm->username = username;
  1001.             /* Added by marca. */
  1002.             if (!realm->username)
  1003.               return "";
  1004.     }
  1005.     password = HTPromptPassword("Enter password to authenticate yourself: ");
  1006.     FREE(realm->password);
  1007.     realm->password = password;
  1008.         /* Added by marca. */
  1009.         if (!realm->password)
  1010.           return "";
  1011.     }
  1012.     
  1013.     len = strlen(realm->username ? realm->username : "") +
  1014.       strlen(realm->password ? realm->password : "") + 3;
  1015.  
  1016.     if (scheme == HTAA_PUBKEY) {
  1017. #ifdef PUBKEY
  1018.     /* Generate new secret key */
  1019.     StrAllocCopy(secret_key, HTAA_generateRandomKey());
  1020. #endif
  1021.     /* Room for secret key, timestamp and inet address */
  1022.     len += strlen(secret_key ? secret_key : "") + 30;
  1023.     }
  1024.     else
  1025.     FREE(secret_key);
  1026.  
  1027.     if (!(cleartext  = (char*)calloc(len, 1)))
  1028.     outofmem(__FILE__, "compose_auth_string");
  1029.  
  1030.     if (realm->username) strcpy(cleartext, realm->username);
  1031.     else *cleartext = (char)0;
  1032.  
  1033.     strcat(cleartext, ":");
  1034.  
  1035.     if (realm->password) strcat(cleartext, realm->password);
  1036.  
  1037.     if (scheme == HTAA_PUBKEY) {
  1038.     strcat(cleartext, ":");
  1039.     strcat(cleartext, inet_addr);
  1040.     strcat(cleartext, ":");
  1041.     strcat(cleartext, timestamp);
  1042.     strcat(cleartext, ":");
  1043.     if (secret_key) strcat(cleartext, secret_key);
  1044.  
  1045.     if (!((ciphertext = (char*)malloc(2*len)) &&
  1046.           (result     = (char*)malloc(3*len))))
  1047.         outofmem(__FILE__, "compose_auth_string");
  1048. #ifdef PUBKEY
  1049.     HTPK_encrypt(cleartext, ciphertext, server->public_key);
  1050.         /* marca added unsigned char * cast for HP. */
  1051.     HTUU_encode((unsigned char *)ciphertext, strlen(ciphertext), result);
  1052. #endif
  1053.     free(cleartext);
  1054.     free(ciphertext);
  1055.     }
  1056.     else { /* scheme == HTAA_BASIC */
  1057.       /* Added "+ 1" marca. */
  1058. #ifdef OLD
  1059.     if (!(result = (char*)malloc(len + len/2 + 1)))
  1060. #else
  1061.         /* Ari fix. */
  1062.     if (!(result = (char*)malloc(4 * ((len+2)/3) + 1)))
  1063. #endif
  1064.         outofmem(__FILE__, "compose_auth_string");
  1065.         /* Added cast to unsigned char * on advice of
  1066.            erik@sockdev.uni-c.dk (Erik Bertelsen). */
  1067.     HTUU_encode((unsigned char *)cleartext, strlen(cleartext), result);
  1068.     free(cleartext);
  1069.     }
  1070.     if(TRACE) fprintf(stderr,"sending auth line: %s\n",result);
  1071.     return result;
  1072. }
  1073.  
  1074.  
  1075.  
  1076.  
  1077. /* BROWSER PUBLIC                    HTAA_composeAuth()
  1078. **
  1079. **    SELECT THE AUTHENTICATION SCHEME AND
  1080. **    COMPOSE THE ENTIRE AUTHORIZATION HEADER LINE
  1081. **    IF WE ALREADY KNOW THAT THE HOST REQUIRES AUTHENTICATION
  1082. **
  1083. ** ON ENTRY:
  1084. **    hostname    is the hostname of the server.
  1085. **    portnumber    is the portnumber in which the server runs.
  1086. **    docname        is the pathname of the document (as in URL)
  1087. **
  1088. ** ON EXIT:
  1089. **    returns    NULL, if no authorization seems to be needed, or
  1090. **        if it is the entire Authorization: line, e.g.
  1091. **
  1092. **           "Authorization: Basic username:password"
  1093. **
  1094. **        As usual, this string is automatically freed.
  1095. */
  1096. PUBLIC char *HTAA_composeAuth ARGS3(CONST char *,    hostname,
  1097.                     CONST int,        portnumber,
  1098.                     CONST char *,    docname)
  1099. {
  1100.     static char *result = NULL;
  1101.     char *auth_string;
  1102.     BOOL retry;
  1103.     HTAAScheme scheme;
  1104.  
  1105.     FREE(result);            /* From previous call */
  1106.  
  1107.     if (TRACE)
  1108.     fprintf(stderr, 
  1109.         "Composing Authorization for %s:%d/%s\n",
  1110.         hostname, portnumber, docname);
  1111.  
  1112.     if (current_portnumber != portnumber ||
  1113.     !current_hostname || !current_docname ||
  1114.     !hostname         || !docname         ||
  1115.     0 != strcmp(current_hostname, hostname) ||
  1116.     0 != strcmp(current_docname, docname)) {
  1117.  
  1118.     retry = NO;
  1119.  
  1120.     current_portnumber = portnumber;
  1121.     
  1122.     if (hostname) StrAllocCopy(current_hostname, hostname);
  1123.     else FREE(current_hostname);
  1124.  
  1125.     if (docname) StrAllocCopy(current_docname, docname);
  1126.     else FREE(current_docname);
  1127.     }
  1128.     else retry = YES;
  1129.     
  1130.     if (!current_setup || !retry)
  1131.     current_setup = HTAASetup_lookup(hostname, portnumber, docname);
  1132.  
  1133.     if (!current_setup)
  1134.     return NULL;
  1135.  
  1136.  
  1137.     switch (scheme = HTAA_selectScheme(current_setup)) {
  1138.       case HTAA_BASIC:
  1139.       case HTAA_PUBKEY:
  1140.     auth_string = compose_auth_string(scheme, current_setup);
  1141.     break;
  1142. #ifdef PEM_AUTH
  1143.       case HTAA_PEM:
  1144.       case HTAA_PGP:
  1145.         return NULL; /* with PEM, no authorization: line in the request */
  1146.         break;
  1147. #endif /* PEM_AUTH */
  1148.       case HTAA_KERBEROS_V4:
  1149.     /* OTHER AUTHENTICATION ROUTINES ARE CALLED HERE */
  1150.       default:
  1151.     {
  1152.         char msg[2048];
  1153.         sprintf(msg, "%s %s `%s'",
  1154.             "This client doesn't know how to compose authentication",
  1155.             "information for scheme", HTAAScheme_name(scheme));
  1156.         HTAlert(msg);
  1157.         auth_string = NULL;
  1158.     }
  1159.     } /* switch scheme */
  1160.  
  1161.     current_setup->retry = NO;
  1162.  
  1163.     /* Added by marca. */
  1164.     if (!auth_string)
  1165.       return NULL;
  1166.  
  1167.     if (!(result = (char*)malloc(sizeof(char) * (strlen(auth_string)+40))))
  1168.     outofmem(__FILE__, "HTAA_composeAuth");
  1169.     strcpy(result, "Authorization: ");
  1170.     strcat(result, HTAAScheme_name(scheme));
  1171.     strcat(result, " ");
  1172.     strcat(result, auth_string);
  1173.     return result;
  1174. }
  1175.  
  1176.  
  1177.  
  1178.         
  1179. /* BROWSER PUBLIC                HTAA_shouldRetryWithAuth()
  1180. **
  1181. **        DETERMINES IF WE SHOULD RETRY THE SERVER
  1182. **        WITH AUTHORIZATION
  1183. **        (OR IF ALREADY RETRIED, WITH A DIFFERENT
  1184. **        USERNAME AND/OR PASSWORD (IF MISSPELLED))
  1185. ** ON ENTRY:
  1186. **    start_of_headers is the first block already read from socket,
  1187. **            but status line skipped; i.e. points to the
  1188. **            start of the header section.
  1189. **    length        is the remaining length of the first block.
  1190. **    soc        is the socket to read the rest of server reply.
  1191. **
  1192. **            This function should only be called when
  1193. **            server has replied with a 401 (Unauthorized)
  1194. **            status code.
  1195. ** ON EXIT:
  1196. **    returns        YES, if connection should be retried.
  1197. **                 The node containing all the necessary
  1198. **                 information is
  1199. **                * either constructed if it does not exist
  1200. **                * or password is reset to NULL to indicate
  1201. **                  that username and password should be
  1202. **                  reprompted when composing Authorization:
  1203. **                  field (in function HTAA_composeAuth()).
  1204. **            NO, otherwise.
  1205. */
  1206. PUBLIC BOOL HTAA_shouldRetryWithAuth ARGS3(char *, start_of_headers,
  1207.                        int,       length,
  1208.                        int,       soc)
  1209. {
  1210.     HTAAScheme scheme;
  1211.     char *line;
  1212.     int num_schemes = 0;
  1213.     HTList *valid_schemes = HTList_new();
  1214.     HTAssocList **scheme_specifics = NULL;
  1215.     char *template = NULL;
  1216.  
  1217.  
  1218.     /* Read server reply header lines */
  1219.  
  1220.     if (TRACE)
  1221.     fprintf(stderr, "Server reply header lines:\n");
  1222.  
  1223.     HTAA_setupReader(start_of_headers, length, soc);
  1224.     while (NULL != (line = HTAA_getUnfoldedLine())  &&  *line != (char)0) {
  1225.  
  1226.     if (TRACE) fprintf(stderr, "%s\n", line);
  1227.  
  1228.     if (strchr(line, ':')) {    /* Valid header line */
  1229.  
  1230.         char *p = line;
  1231.         char *fieldname = HTNextField(&p);
  1232.         char *arg1 = HTNextField(&p);
  1233.         char *args = p;
  1234.         
  1235.         if (0==strcasecomp(fieldname, "WWW-Authenticate:")) {
  1236.         if (HTAA_UNKNOWN != (scheme = HTAAScheme_enum(arg1))) {
  1237.             HTList_addObject(valid_schemes, (void*)scheme);
  1238.             if (!scheme_specifics) {
  1239.             int i;
  1240.             scheme_specifics = (HTAssocList**)
  1241.                 malloc(HTAA_MAX_SCHEMES * sizeof(HTAssocList*));
  1242.             if (!scheme_specifics)
  1243.                 outofmem(__FILE__, "HTAA_shouldRetryWithAuth");
  1244.             for (i=0; i < HTAA_MAX_SCHEMES; i++)
  1245.                 scheme_specifics[i] = NULL;
  1246.             }
  1247.             scheme_specifics[scheme] = HTAA_parseArgList(args);
  1248.             num_schemes++;
  1249.         }
  1250.         else if (TRACE) {
  1251.             fprintf(stderr, "Unknown scheme `%s' %s\n",
  1252.                 (arg1 ? arg1 : "(null)"),
  1253.                 "in WWW-Authenticate: field");
  1254.         }
  1255.         }
  1256.  
  1257.         else if (0==strcasecomp(fieldname, "WWW-Protection-Template:")) {
  1258.         if (TRACE)
  1259.             fprintf(stderr, "Protection template set to `%s'\n", arg1);
  1260.         StrAllocCopy(template, arg1);
  1261.         }
  1262.  
  1263.     } /* if a valid header line */
  1264.     else if (TRACE) {
  1265.         fprintf(stderr, "Invalid header line `%s' ignored\n", line);
  1266.     } /* else invalid header line */
  1267.     } /* while header lines remain */
  1268.  
  1269.  
  1270.     /* So should we retry with authorization */
  1271.  
  1272.     if (num_schemes == 0) {        /* No authentication valid */
  1273.     current_setup = NULL;
  1274.     return NO;
  1275.     }
  1276.  
  1277.     if (current_setup && current_setup->server) {
  1278.     /* So we have already tried with authorization.    */
  1279.     /* Either we don't have access or username or    */
  1280.     /* password was misspelled.            */
  1281.         
  1282.     /* Update scheme-specific parameters    */
  1283.     /* (in case they have expired by chance).    */
  1284.     HTAASetup_updateSpecifics(current_setup, scheme_specifics);
  1285.  
  1286.     if (NO == HTConfirm("Authorization failed.  Retry?")) {
  1287.         current_setup = NULL;
  1288.         return NO;
  1289.     } /* HTConfirm(...) == NO */
  1290.     else { /* re-ask username+password (if misspelled) */
  1291.         current_setup->retry = YES;
  1292.         return YES;
  1293.     } /* HTConfirm(...) == YES */
  1294.     } /* if current_setup != NULL */
  1295.  
  1296.     else { /* current_setup == NULL, i.e. we have a     */
  1297.        /* first connection to a protected server or  */
  1298.        /* the server serves a wider set of documents */
  1299.        /* than we expected so far.                   */
  1300.  
  1301.     HTAAServer *server = HTAAServer_lookup(current_hostname,
  1302.                            current_portnumber);
  1303.     if (!server) {
  1304.         server = HTAAServer_new(current_hostname,
  1305.                     current_portnumber);
  1306.     }
  1307.     if (!template)
  1308.         template = HTAA_makeProtectionTemplate(current_docname);
  1309.     current_setup = HTAASetup_new(server, 
  1310.                       template,
  1311.                       valid_schemes,
  1312.                       scheme_specifics);
  1313.  
  1314.         HTAlert("Access without authorization denied -- retrying");
  1315.     return YES;
  1316.     } /* else current_setup == NULL */
  1317.  
  1318.     /* Never reached */
  1319. }
  1320.  
  1321.  
  1322.  
  1323. #ifdef PEM_AUTH
  1324. /* BROWSER PUBLIC                HTAA_TryWithAuth()
  1325. **
  1326. **        SAYS WE KNOW WE SHOULD TRY THE SERVER
  1327. **        WITH AUTHORIZATION RIGHT FROM THE START
  1328. ** ON ENTRY:
  1329. **    enctype            is the string we were given to determine
  1330. **            just what type of authorization we should ask for
  1331. **            from the start.
  1332. **      entity          is the server identifier needed by some
  1333. **                      types of authorization.
  1334. **    action            is the url we are GETing or POSTing to.
  1335. **
  1336. **            This function should only be called when
  1337. **            when we are responding to a form with ENCTYPE set.
  1338. ** ON EXIT:
  1339. **    returns        YES
  1340. **                 The node containing all the necessary
  1341. **                 information is constructed.
  1342. **            NO
  1343. **                 Client can't do this encryption type.
  1344. */
  1345. PUBLIC BOOL HTAA_TryWithAuth ARGS3(char *, enctype, char *, entity,
  1346.                     char *, action)
  1347. {
  1348.     HTAAScheme scheme;
  1349.     char *line;
  1350.     int num_schemes = 0;
  1351.     HTList *valid_schemes = HTList_new();
  1352.     HTAssocList **scheme_specifics = NULL;
  1353.     char *template = NULL;
  1354.     char *rem_entity = NULL;
  1355.     int type;
  1356.     char *encrypt;
  1357.     char *hostname;
  1358.     int portnumber;
  1359.  
  1360. {
  1361.     char *docname;
  1362.     char *colon;
  1363.     char *auth;
  1364.  
  1365.  
  1366.     docname = HTParse(action, "", PARSE_PATH);
  1367.     hostname = HTParse(action, "", PARSE_HOST);
  1368.     if (hostname &&
  1369.         NULL != (colon = strchr(hostname, ':')))
  1370.       {
  1371.         *(colon++) = '\0';  /* Chop off port number */
  1372.         portnumber = atoi(colon);
  1373.       }
  1374.     else portnumber = 80;
  1375.  
  1376.     auth = HTAA_composeAuth(hostname, portnumber, docname);
  1377.  
  1378.     FREE(docname);
  1379. }
  1380.  
  1381.     if (entity) {
  1382.         rem_entity = (char *)malloc(strlen(entity) +
  1383.             strlen("entity=\"\"") + 1);
  1384.         sprintf(rem_entity, "entity=\"%s\"", entity);
  1385.     }
  1386.     else {
  1387.         rem_entity = (char *)malloc(strlen(hostname) + 20 +
  1388.             strlen("entity=\"\"") + 1);
  1389.         sprintf(rem_entity, "entity=\"%s:%d\"", hostname, portnumber);
  1390.     }
  1391.  
  1392.     FREE(hostname);
  1393.  
  1394.     scheme = HTAAScheme_enum(enctype);
  1395.     if (scheme != HTAA_UNKNOWN) {
  1396.         HTList_addObject(valid_schemes, (void*)scheme);
  1397.         if (!scheme_specifics) {
  1398.             int i;
  1399.             scheme_specifics = (HTAssocList**)
  1400.                 malloc(HTAA_MAX_SCHEMES * sizeof(HTAssocList*));
  1401.             if (!scheme_specifics)
  1402.                 outofmem(__FILE__, "HTAA_TryWithAuth");
  1403.             for (i=0; i < HTAA_MAX_SCHEMES; i++)
  1404.                 scheme_specifics[i] = NULL;
  1405.         }
  1406.         scheme_specifics[scheme] = HTAA_parseArgList(rem_entity);
  1407.         num_schemes++;
  1408.     }
  1409.     else if (TRACE) {
  1410.         fprintf(stderr, "Unknown scheme `%s' %s\n",
  1411.             (enctype ? enctype : "(null)"),
  1412.             "in ENCTYPE field");
  1413.     }
  1414.  
  1415.     if (rem_entity) {
  1416.         free(rem_entity);
  1417.     }
  1418.         
  1419.     /* So do we have an understood authorization scheme? */
  1420.  
  1421.     if (num_schemes == 0) {        /* No authentication valid */
  1422.     current_setup = NULL;
  1423.     return NO;
  1424.     }
  1425.  
  1426.     {
  1427.     HTAAServer *server = HTAAServer_lookup(current_hostname,
  1428.                            current_portnumber);
  1429.     if (!server) {
  1430.         server = HTAAServer_new(current_hostname,
  1431.                     current_portnumber);
  1432.     }
  1433.     if (!template)
  1434.         template = HTAA_makeProtectionTemplate(current_docname);
  1435.     current_setup = HTAASetup_new(server, 
  1436.                       template,
  1437.                       valid_schemes,
  1438.                       scheme_specifics);
  1439.     }
  1440.  
  1441.     if(!current_setup)
  1442.         return NO;
  1443.  
  1444.     type = HTAA_selectScheme(current_setup);
  1445.     if((type != HTAA_PEM) && (type != HTAA_PGP))
  1446.         return NO;
  1447.  
  1448.     encrypt = (type == HTAA_PEM ? HTAA_PEMencrypt : HTAA_PGPencrypt);
  1449.  
  1450.     if (!encrypt)
  1451.         return NO;
  1452.  
  1453.     return YES;
  1454. }
  1455.  
  1456. PUBLIC void HTAA_ClearAuth NOARGS
  1457. {
  1458.  
  1459.     HTAAServerTable_delete (server_table);
  1460.     current_setup = NULL;
  1461.     current_hostname = NULL;
  1462.     current_portnumber = 80;
  1463.     current_docname = NULL;
  1464. }
  1465. #endif /* PEM_AUTH */
  1466.  
  1467.